package com.mk.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.hutool.core.net.url.UrlBuilder;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mk.constant.MessageConstant;
import com.mk.constant.RedisCacheConstant;
import com.mk.context.BaseContext;
import com.mk.dto.UserLoginDTO;
import com.mk.entity.User;
import com.mk.exception.*;
import com.mk.mapper.UserMapper;
import com.mk.properties.WeChatProperties;
import com.mk.service.IUserService;
import com.mk.utils.HttpClientUtil;
import com.mk.utils.RedisUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * 用户端微信用户登录接口实现类
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService, UserDetailsService {
    /*//微信服务接口地址
    public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";
    //微信小程序获取手机号
    public static final String WX_PHONE = "https://api.weixin.qq.com/wxa/business/getuserphonenumber";*/

    private final WeChatProperties weChatProperties;

    private final WxMaService wxMaService;

    private final UserMapper userMapper;

    private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    private final RedisTemplate<String, String> redisTemplate;



    /**
     * 账号密码登录
     * @param userLoginDTO
     * @return
     */
    @Override
    public User login(UserLoginDTO userLoginDTO) {
        String username = userLoginDTO.getUsername();
        String password = userLoginDTO.getPassword();

        //1、根据用户名查询数据库中的数据
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getUsername, username).select());

        //2、处理各种异常情况（用户名不存在、密码不对、账号被锁定）
        if (user == null) {
            //账号不存在
            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }

        //密码比对
        //对前端传过来的明文密码进行md5加密处理
//        password = DigestUtils.md5DigestAsHex(password.getBytes());
        //对前端传过来的明文密码进行BCrypt算法加密处理并比较
        if (!passwordEncoder.matches(password, user.getPassword())) {
            //密码错误
            throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
        }

        user.setStatus(User.ONLINE);
        user.setOnlineTime(LocalDateTime.now());
        userMapper.updateById(user);

        //3、返回实体对象
        return user;
    }

    /**
     * 用户注册
     *
     * @param userLoginDTO
     */
    @Override
    public void register(UserLoginDTO userLoginDTO) {
        LocalDateTime createTime = LocalDateTime.now();
//        if (!userLoginDTO.getPassword().equals(userLoginDTO.getConfirmPassword())) {
//            throw new PasswordErrorException(MessageConstant.PASSWORD_NOT_CONFIRM);
//        }
//        if (!userLoginDTO.getSecurityCode().equals(userLoginDTO.getConfirmSecurityCode())) {
//            throw new SecurityCodeException(MessageConstant.SECURITY_CODE_NOT_CONFIRM);
//        }
        String username = userLoginDTO.getUsername();
        String password = userLoginDTO.getPassword();
        //判断用户名是否已经存在
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getUsername, username));
        if (user != null) {
            throw new UserAlreadyExistException(MessageConstant.ALREADY_EXISTS);
        }
//        String password = DigestUtils.md5DigestAsHex(userLoginDTO.getPassword().getBytes());

        String encryptedPassword = passwordEncoder.encode(password);
        userMapper.insert(User.builder()
                .username(username)
                .password(encryptedPassword)
                .createTime(createTime)
                .build());
        RedisUtil redisUtil = new RedisUtil(redisTemplate);
        redisUtil.set(RedisCacheConstant.USER_LOGIN_KEY + username, "");
    }

    /**
     * SpringSecurity用户认证
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getUsername, username).select());
        if (user == null) {
            throw new UsernameNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }
        //将用户唯一id存入ThreadLocal全局变量
        BaseContext.setCurrentId(user.getId());
        return user;
    }

    /**
     * 微信登录
     * @param userLoginDTO
     * @return
     *//*
    @Override
    public User wxLogin(UserLoginDTO userLoginDTO) {

        String openid = getOpenid(userLoginDTO.getCode());

        //判断openid是否为空，如果为空表示登录失败，抛出业务异常
        if (openid == null){
            throw new LoginFailedException(MessageConstant.LOGIN_FAILED);
        }

        //判断当前用户是否为新用户
        User user = userMapper.getByOpenid(openid);

        //如果是新用户，自动完成注册
        if (user == null){
            user = User.builder()
                    .openid(openid)
                    .status(User.ONLINE)
                    .createTime(LocalDateTime.now())
                    .onlineTime(LocalDateTime.now())
                    .build();
            userMapper.insert(user);
        } else {
            user.setStatus(User.ONLINE);
            user.setOnlineTime(LocalDateTime.now());
        }

        //返回这个用户
        return user;
    }

    *//**
     * 微信手机号一键登录
     * @param userLoginDTO
     * @return
     * @throws IOException
     *//*
    @Override
    public User wxLoginByPhone(UserLoginDTO userLoginDTO) throws IOException {
        String openid = getOpenid(userLoginDTO.getCode());

        //判断openid是否为空，如果为空表示登录失败，抛出业务异常
        if (openid == null){
            throw new LoginFailedException(MessageConstant.LOGIN_FAILED);
        }

        //判断当前用户是否为新用户
        User user = userMapper.getByOpenid(openid);

        String phone = getMobilePhoneByWx(userLoginDTO.getCode());

        //如果是新用户，自动完成注册
        if (user == null){
            user = User.builder()
                    .openid(openid)
                    .phone(phone)
                    .status(User.ONLINE)
                    .createTime(LocalDateTime.now())
                    .onlineTime(LocalDateTime.now())
                    .build();
            userMapper.insert(user);
        } else {
            user.setStatus(User.ONLINE);
            user.setOnlineTime(LocalDateTime.now());
        }

        //返回这个用户
        return user;
    }*/


   /* *//**
     * 获取微信用户手机号
     * @param code
     * @return
     * @throws IOException
     *//*
    private String getMobilePhoneByWx(String code) throws IOException {
        try {
            String accessToken = wxMaService.getAccessToken();
            String url = UrlBuilder.of(WX_PHONE).addQuery("access_token", accessToken).build();
            Map<String, String> paramBody = new HashMap<>(2);
            paramBody.put("code", code);
            String result = HttpClientUtil.doPost(url, paramBody);
            JSONObject jsonObject = JSON.parseObject(result);
            if ("40029".equals(jsonObject.getString("errcode"))){
                throw new LoginFailedException(MessageConstant.CODE_INVALID);
            }
            if ("-1".equals(jsonObject.getString("errcode"))){
                throw new LoginFailedException(MessageConstant.WX_SYSTEM_BUSY);
            }
            JSONObject phoneInfo = jsonObject.getJSONObject("phone_info");
            return phoneInfo.getString("phoneNumber");
        } catch (WxErrorException e) {
            e.printStackTrace();
            throw new LoginFailedException(MessageConstant.PHONE_FAILED);
        }
    }




    *//**
     * 调用微信接口服务，获取微信用户的openid
     * @param code
     * @return
     *//*
    private String getOpenid(String code) {
        //调用微信接口服务，获得当前微信用户的openid
        Map<String, String> map = new HashMap<>();
        map.put("appid",weChatProperties.getAppid());
        map.put("secret",weChatProperties.getSecret());
        map.put("js_code",code);
        map.put("grant_type", "authorization_code");
        String json = HttpClientUtil.doGet(WX_LOGIN, map);

        JSONObject jsonObject = JSON.parseObject(json);
        String openid = jsonObject.getString("openid");
        return openid;
    }*/
}
